from google.appengine.ext import db
import array
import logging
import png
import StringIO

from pixeltoy import colorlib


class Props(object): pass


grid_size = Props()
grid_size.width = 32
grid_size.height = 32
snapshot_pixel_size = colorlib.snapshot_pixel_size


class Pixels(db.Model):
  """A grid of pixels where each pixel is an index into a color list."""
  width = db.IntegerProperty(required=True)
  height = db.IntegerProperty(required=True)
  colors = db.StringListProperty()
  pixels = db.BlobProperty()

  def apply_stroke(self, data_as_string):
    data = data_as_string.split('_')
    try:
      color_index = int(data[0][1:])
      bytes = list(self.pixels)
      for coord in data[1:]:
        (x_str,y_str) = coord.split(".")
        x = int(x_str)
        y = int(y_str)
        if (x >= 0 and x < self.width and y >= 0 and y < self.height):
          bytes[x + y * self.width] = chr(color_index)
      self.pixels = ''.join(bytes)
    except ValueError:
      logging.warn("unable to apply stroke: '%s'" % data_as_string)
      raise
    Pixels.pixels.validate(self.pixels)

  def to_snapshot(self):
    rgb = array.array('B')
    for y in xrange(0, self.height):
      line = array.array('B')
      for x in xrange(0, self.width):
        color_index = self.pixels[y * self.width + x]
        color_name = self.colors[ord(color_index)]
        line.extend(colorlib.color_rgb_chunks[color_name])
      for i in xrange (0, snapshot_pixel_size):
        rgb.extend(line)

    png_data = StringIO.StringIO()
    snapshot_width = self.width * snapshot_pixel_size
    snapshot_height = self.height * snapshot_pixel_size
    writer = png.Writer(width=snapshot_width,
                        height=snapshot_height)
    writer.write_array(png_data, rgb)
    return Snapshot(width=snapshot_width, height=snapshot_height,
                    data=png_data.getvalue())


class SnapshotAction(db.Model):
  action_type = db.CategoryProperty(required=True)
  date_done = db.DateTimeProperty(required=True, auto_now_add=True)
  done_by = db.UserProperty()


class Snapshot(db.Model):
  """A snapshot of pixeltoy, converted to a PNG"""
  name = db.StringProperty(required=True, default="Untitled")
  date_created = db.DateTimeProperty(required=True, auto_now_add=True)
  width = db.IntegerProperty(required=True)
  height = db.IntegerProperty(required=True)
  data = db.BlobProperty()  
  hidden = db.ReferenceProperty(reference_class=SnapshotAction, default=None)
  is_hidden = db.BooleanProperty(default=False)
  can_hide = db.BooleanProperty(default=True, required=True)


def make_empty_pixels(width=grid_size.width, height=grid_size.height):
  return Pixels(key_name='singleton',
                width = width,
                height = height,
                colors = colorlib.color_names,
                pixels = chr(0) * (grid_size.width * grid_size.height))


def get_pixels():
  result = Pixels.get_by_key_name('singleton')
  if result is None:
    return make_empty_pixels()
  else:
    return result
